package com.czmh.etc.onlinepubsys.controller;

import com.czmh.etc.common.core.annotation.ApiVersion;
import com.czmh.etc.common.core.utils.IpUtil;
import com.czmh.etc.onlinepubsys.enums.PayWayEnum;
import com.czmh.etc.onlinepubsys.services.EtcOrderService;
import com.czmh.etc.onlinepubsys.utils.MD5Utils;
import com.czmh.etc.onlinepubsys.utils.WeiXinPayUtils;
import com.czmh.etc.onlinepubsys.utils.wxpay.StringUtil;
import com.github.wxpay.sdk.WXPayUtil;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;

/**
 * @author sevenchen
 * @date 2019年06月25日18:48:27
 */
@Controller
@RequestMapping(value = "/{version}/scanPayNotify")
public class PayNotifyController {
	private static final Log LOG = LogFactory.getLog(PayNotifyController.class);
	/**
	 * 微信订单异步通知信息前缀修饰
	 */
	private static final String WXPAY_ORDER_NOTIFY_REDIS_KEY = "WXPAY_ORDER_NOTIFY_";
	/**
	 * 支付宝订单异步通知信息前缀修饰
	 */
	private static final String ALIPAY_ORDER_NOTIFY_REDIS_KEY = "ALIPAY_ORDER_NOTIFY_";
	
    @Value("${wx.wxPayAppSecret}")
    private String                      wxPayAppSecret;

	@Autowired
	private EtcOrderService etcOrderService;

	/**
	 * 支付成功后的异步通知.
	 * 
	 * @param payWayCode 支付方式
	 * @param httpServletRequest http请求对象
	 * @param httpServletResponse http相应对象
	 * @throws Exception
	 */
	@ApiVersion(1)
	@RequestMapping("/notify/{payWayCode}")
	public void notify(@PathVariable("payWayCode") String payWayCode, HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse) throws Exception {
		LOG.info("into notify,payWayCode:" + payWayCode);
		String remoteIpAddr = IpUtil.getIpAddr(httpServletRequest);
		LOG.info("remoteIpAddr:" + remoteIpAddr);
		String printStr = "";
		Map<String, String> notifyMap = new HashMap<String, String>(0);
		if (PayWayEnum.WEIXIN.name().equals(payWayCode)) {
			// 从request中取得输入流
			InputStream inputStream = httpServletRequest.getInputStream();
			notifyMap = WeiXinPayUtils.parseXml(inputStream);
		} else if (PayWayEnum.ALIPAY.name().equals(payWayCode)) {
		    // 支付宝支付暂不处理
		}
        Boolean flag = etcOrderService.verifyNotify(payWayCode, notifyMap);
		// 后续业务处理(由于微信和支付宝会多次回调所以实际操作时要进行幂等判断)
		if (flag) {
			if (PayWayEnum.WEIXIN.name().equals(payWayCode)) {
				// 处理支付通知校验成功后的业务逻辑
				etcOrderService.dealPaymentNotifySuccess(payWayCode, notifyMap);
				printStr = "<xml>\n" + 
						   "  <return_code><![CDATA[SUCCESS]]></return_code>\n" + 
						   "  <return_msg><![CDATA[OK]]></return_msg>\n" + 
						   "</xml>";
			} else if (PayWayEnum.ALIPAY.name().equals(payWayCode)) {
				// 处理支付通知校验成功后的业务逻辑
			}
		}

		if (!StringUtil.isEmpty(printStr)) {
			httpServletResponse.getWriter().print(printStr);
		}
	}
	
	/**
	 * 申请退款成功后的异步通知.
	 * 
	 * @param payWayCode 支付方式
	 * @param httpServletRequest http请求对象
	 * @param httpServletResponse http相应对象
	 * @throws Exception
	 */
	@ApiVersion(1)
	@RequestMapping("/refund/notify/{payWayCode}")
	public void refundNotify(@PathVariable("payWayCode") String payWayCode, HttpServletRequest httpServletRequest,
	        HttpServletResponse httpServletResponse) throws Exception {
	    LOG.info("into notify,payWayCode:" + payWayCode);
	    String remoteIpAddr = IpUtil.getIpAddr(httpServletRequest);
	    LOG.info("remoteIpAddr:" + remoteIpAddr);
	    String printStr = "";
	    Map<String, String> notifyMap = new HashMap<String, String>(0);
	    if (PayWayEnum.WEIXIN.name().equals(payWayCode)) {
	        // 从request中取得输入流
	        InputStream inputStream = httpServletRequest.getInputStream();
	        notifyMap = WeiXinPayUtils.parseXml(inputStream);
	        if ("SUCCESS".equals(notifyMap.get("return_code"))) {
	            String reqInfo = notifyMap.get("req_info");// 退款返回加密信息
	            //对商户key做md5
	            String keyMd5 = MD5Utils.getMD5(wxPayAppSecret).toLowerCase();
	            //对加密串req_info做base64解码
	            byte[] decodeReqInfo = Base64.decodeBase64(reqInfo);
	            //PKCS7Padding填充方式
	            Security.addProvider(new BouncyCastleProvider());
	            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");  
	            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyMd5.getBytes(), "AES"));
	              
	            byte[] decoded = cipher.doFinal(decodeReqInfo);
	            //获取解密后的返回串，这个才是真正需要的数据
	            String decryptInfo = new String(decoded, "UTF-8");
	            //将返回串转换成 Map
	            Map<String, String> reqInfoMap = WXPayUtil.xmlToMap(decryptInfo);
	            String out_trade_no = reqInfoMap.get("out_trade_no");
	            // 更新订单退款状态
	            etcOrderService.updateOrderRefund(out_trade_no);
	            printStr = "<xml>\n" + 
                        "  <return_code><![CDATA[SUCCESS]]></return_code>\n" + 
                        "  <return_msg><![CDATA[OK]]></return_msg>\n" + 
                        "</xml>";
	      }
	    } else if (PayWayEnum.ALIPAY.name().equals(payWayCode)) {
	        // 支付宝支付暂不处理
	    }
	    
	    if (!StringUtil.isEmpty(printStr)) {
	        httpServletResponse.getWriter().print(printStr);
	    }
	}
}